package org.the.gsdo.client;

import org.the.gsdo.client.GwtSpring.ServiceLocator;
import org.the.gsdo.shared.FieldVerifier;
import org.the.gsdo.shared.SendTextToServer;
import org.the.gsdo.shared.SendTextToServerResult;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceTokenizer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;

public class InputPanel extends BasePanel {

	private HTMLPanel htmlPanel;
	private TextBox nameField;
	private Label errorLabel;

	public InputPanel() {
		htmlPanel = new HTMLPanel(GsdoResources.INSTANCE.inputHtml().getText());

		final Button sendButton = new Button("Send");
		nameField = new TextBox();
		nameField.setText("GWT User");
		errorLabel = new Label();

		// We can add style names to widgets
		sendButton.addStyleName("sendButton");

		htmlPanel.add(nameField, "nameFieldContainer");
		htmlPanel.add(sendButton, "sendButtonContainer");
		htmlPanel.add(errorLabel, "errorLabelContainer");

		// Focus the cursor on the name field when the app loads
		initWidget(htmlPanel);

		// Add a handler to send the name to the server
		MyHandler handler = new MyHandler() {

			@Override
			public void sendNameToServer() {
				// First, we validate the input.
				errorLabel.setText("");
				String textToServer = nameField.getText();
				if (!FieldVerifier.isValidName(textToServer)) {
					errorLabel.setText("Please enter at least four characters");
					return;
				}
				// Then, we send the input to the server.
				sendButton.setEnabled(false);
				ServiceLocator.getService().execute(
						new SendTextToServer(textToServer),
						new AsyncCallback<SendTextToServerResult>() {
							@Override
							public void onFailure(Throwable caught) {
								sendButton.setEnabled(true);
								placeController.goTo(new ResponsePanel.ResponsePlace(SERVER_ERROR));
							}
							@Override
							public void onSuccess(SendTextToServerResult result) {
								sendButton.setEnabled(true);
								placeController.goTo(new ResponsePanel.ResponsePlace(result));
							}
						});
			}
		};
		sendButton.addClickHandler(handler);
		nameField.addKeyUpHandler(handler);
	}

	@Override
	public void onShow() {
		// to get the selection and the focus
		init();
	}

	@Override
	public void nextPlace(Place place) {
		// noop right here
	}

	@Override
	protected void onLoad() {
		super.onLoad();
		// to get focus and the selection
		init();
	}

	private void init() {
		nameField.setFocus(true);
		nameField.selectAll();
	}

	private static abstract class MyHandler implements ClickHandler, KeyUpHandler {
		/**
		 * Fired when the user clicks on the sendButton.
		 */
		@Override
		public void onClick(ClickEvent event) {
			sendNameToServer();
		}

		/**
		 * Fired when the user types in the nameField.
		 */
		@Override
		public void onKeyUp(KeyUpEvent event) {
			if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
				sendNameToServer();
			}
		}

		/**
		 * Send the name from the nameField to the server and wait for a response.
		 */
		public abstract void sendNameToServer();

	}

	public static class InputActivity extends AbstractActivity {

		private InputPanel inputPanel;

		@Override
		public void start(AcceptsOneWidget panel, EventBus eventBus) {
			panel.setWidget(getView());
		}

		public IsPlaceWidget getView() {
			if (inputPanel == null) {
				inputPanel = new InputPanel();
			}
			return inputPanel;
		}

		public InputActivity nextPlace(Place place) {
			getView().nextPlace(place);
			return this;
		}

		public InputActivity with(PlaceController placeController) {
			getView().withController(placeController);
			return this;
		}

	}

	public static class InputPlace extends Place {

		public InputPlace() {}

		public String getName() {
			return "input";
		}

		public static class Tokenizer implements PlaceTokenizer<InputPlace> {

			@Override
			public InputPlace getPlace(String token) {
				return new InputPlace();
			}

			@Override
			public String getToken(InputPlace place) {
				return place.getName();
			}

		}
	}

}
